package com.inspectortime.webapp.inspector;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.mvc.SimpleFormController;

import com.inspectortime.domain.EmailTemplate;
import com.inspectortime.domain.Inspection;
import com.inspectortime.domain.InspectorCompany;
import com.inspectortime.domain.RealEstateAgent;
import com.inspectortime.domain.type.State;
import com.inspectortime.mail.service.DynamicMailMessage;
import com.inspectortime.mail.service.EmailDeliveryException;
import com.inspectortime.repository.Factory;
import com.inspectortime.repository.Repository;
import com.inspectortime.util.CalendarUtil;
import com.inspectortime.util.SpringValidatorUtils;
import com.inspectortime.webapp.util.HttpSessionUtils;

import freemarker.template.Configuration;
import freemarker.template.SimpleHash;
import freemarker.template.TemplateModelException;
import freemarker.template.utility.XmlEscape;

public class EmailTemplateFormController extends SimpleFormController {

	private static Log log = LogFactory
			.getLog(EmailTemplateFormController.class);
	private Repository repository;
	private Factory factory;
	private Configuration freemarkerConfiguration;

	protected Map referenceData(HttpServletRequest request) throws Exception {
		Map<String, Object> data = new HashMap<String, Object>();

		return data;
	}

	protected Object formBackingObject(HttpServletRequest request)
			throws Exception {

		InspectorCompany company = HttpSessionUtils.retrieveLoggedInCompany(
				request, repository);
		EmailTemplate template = null;
		EmailTemplateForm form = new EmailTemplateForm();
		
		//TODO: CONSIDER CREATING A NEW FREEMARKER PAGE FOR THE EDITABLE EMAIL ADDRESSES
		//AND PULL EMAIL NAMES FROM A CONFIG FILE, RATHER THAN A CONSTANT
		String templateName = request.getParameter("emailTemplate.name");
		//Just a lame check to make sure that user doesn't hack the url and create a template with an invalid name
		if (!StringUtils.hasText(templateName) || 
				(!templateName.equals(EmailTemplate.HOME_BUYER_CONFIRMATION_TEMPLATE) && !templateName.equals(EmailTemplate.REALTOR_THANK_YOU_TEMPLATE))) {
			throw new Exception("Invalid templateName");
		}
		
		if (!company.getEmailTemplates().isEmpty()) {
			for (EmailTemplate tempTemplate : company.getEmailTemplates()) {
				if (templateName.equals(tempTemplate.getName())) {
					template = tempTemplate;
					break;
				}
			}
		}
			
		if (template == null) {
			template = factory.createEmailTemplate(templateName, company);
		}
		
		form.setEmailTemplate(template);
		return form;
	}

	/**
	 * Renders an email template into a String property of EmailTemplateForm.
	 * The property will include the error text if FTL rendering error occurs.
	 * 
	 * @param company
	 * @param emailTemplateForm
	 * @return true if no errors, false if error
	 */
	private boolean renderPreview(HttpServletRequest request,
			InspectorCompany company, EmailTemplateForm emailTemplateForm) {

		// Create sample model to use in templates
		Inspection inspection = factory.createInspection();
		inspection.setInspector(company.getInspectors().iterator().next());
		inspection.getHomeBuyer().getName().setFirst("John");
		inspection.getHomeBuyer().getName().setLast("Smith");
		inspection.getHomeBuyer().setEmail("john.smith@email.com");
		inspection.getProperty().getLocation().setStreet1("123 Park Lane");
		inspection.getProperty().getLocation().setStreet2("APT #1");
		inspection.getProperty().getLocation().setCity("Atlanta");
		inspection.getProperty().getLocation().setState(State.GA);
		inspection.getProperty().getLocation().setZipCode("30339");
		Calendar cal = Calendar.getInstance();
		CalendarUtil.setHour(cal, 9);
		inspection.setInspectionTime(cal.getTime());
		
		//include a sample referring agent 
		RealEstateAgent agent = factory.createRealEstateAgent();
		agent.getName().setFirst("Jane");
		agent.getName().setLast("Smith");
		agent.setCompany("Sample Realty");
		agent.setEmail("jane.smith@email.com");
		inspection.setReferringAgent(agent);
		
		// Construct a freemarker configuration instance for rendering.
		// Note that care must be taken to keep the Configuration of the preview
		// the same as the configuration for the actual email renderer (in
		// spring-mail.xml).
		Configuration freemarkerConfiguration = new Configuration();
		Map sharedVariables = new HashMap();
		sharedVariables.put("xml_escape", new XmlEscape());
		try {
			freemarkerConfiguration.setAllSharedVariables(new SimpleHash(sharedVariables));
		} catch (TemplateModelException e1) {
			throw new RuntimeException("Could not set freemarker configuration properties.  Check property names", e1);
		}

		// Create and process a dynamic message to ensure we're using the same
		// logic as an actual email send
		DynamicMailMessage message = new DynamicMailMessage(emailTemplateForm
				.getEmailTemplate(), inspection, request, inspection
				.getHomeBuyer().getEmail());
		try {
			message.processTemplates(freemarkerConfiguration);
			emailTemplateForm.setPreviewBodyHtml(message.getBodyHtml());
			return true;
		} catch (EmailDeliveryException e) {
			StringBuilder sb = new StringBuilder();
			emailTemplateForm.setPreviewBodyHtml(e.getMessage()
					+ "\n\nProblem details:\n" + e.getFtlInstructionStack());
			return false;
		}
	}

	protected void doSubmitAction(Object command) throws Exception {
		EmailTemplateForm form = (EmailTemplateForm) command;
		form.getEmailTemplate().save();
	}

	protected void onBindAndValidate(HttpServletRequest request,
			Object command, BindException errors) throws Exception {
		EmailTemplateForm form = (EmailTemplateForm) command;
		InspectorCompany company = HttpSessionUtils.retrieveLoggedInCompany(
				request, repository);

		// Too short?
		if (form.getEmailTemplate().getSubject().length() < 2) {
			errors.rejectValue("emailTemplate", "template.tooShort",
					"Subject text is too short");
		}
		if (form.getEmailTemplate().getBody().length() < 5) {
			errors.rejectValue("emailTemplate", "template.tooShort",
					"Body text is too short");
		}

		// Validate the entered body template
		if (!renderPreview(request, company, form)) {
			errors.rejectValue("emailTemplate", "template.error",
					"Error in body field template text");
		}

		// Preview mode? If so create an error to force form redisplay
		if (!errors.hasErrors()) {
			String submitValue = request.getParameter("submitButton");
			if (submitValue.equalsIgnoreCase("preview")) {
				errors.rejectValue("emailTemplate", "template.preview",
						"Preview mode, changes have not been saved");
			}
		}

		SpringValidatorUtils.logValidationErrors(log, errors);
	}

	public void setRepository(Repository repository) {
		this.repository = repository;
	}

	public void setFactory(Factory repository) {
		this.factory = repository;
	}
	
	public void setFreemarkerConfiguration(Configuration freemarkerConfiguration) {
		this.freemarkerConfiguration = freemarkerConfiguration;
	}


}
